package com.amtf.datafile3.core.std;

import java.util.ArrayList;
import java.util.List;

import com.amtf.datafile3.DataException;
import com.amtf.datafile3.DataField;
import com.amtf.datafile3.DataFieldDefinition;
import com.amtf.datafile3.DataRecord;
import com.amtf.datafile3.DataTableDefinition;

public class DataRecordImpl implements DataRecord {
	protected DataTableDefinition definition = null;
	protected DataField[] fields = null;
	protected List<String> errors = null;

	public DataRecordImpl(DataTableDefinition definition) {
		this.definition = definition;

		List<DataFieldDefinition> fieldDefs = definition.getFields();
		this.fields = new DataField[fieldDefs.size()];
	}

	public DataRecordImpl(DataTableDefinition definition, boolean initWithDefaultValue) {
		this.definition = definition;

		this.fields = new DataField[definition.getFieldCount()];
		if (initWithDefaultValue) {
			for (int i = 0; i < fields.length; i++) {
				fields[i] = definition.getField(i).newDataFieldInstance();
			}
		}
	}

	public DataField get(int index) {
		return fields[index];
	}

	public DataField get(String name) {
		int i = getFieldIndex(name);
		if (i != -1) {
			return fields[i];
		}

		return null;
	}

	public DataField[] getFields() {
		return fields;
	}

	public Object getValue(int index) {
		if (fields[index] != null) {
			return fields[index].getValue();
		}

		return null;
	}

	public Object getValue(String name) {
		int i = getFieldIndex(name);
		if (i != -1) {
			if (fields[i] != null) {
				return fields[i].getValue();
			}
		}

		return null;
	}

	public String toString() {
		return definition.rending(this);
	}

	public Object[] getValues() {
		Object[] values = new Object[fields.length];
		for (int i = 0; i < fields.length; i++) {
			if (fields[i] != null) {
				values[i] = fields[i].getValue();
			}
		}
		return values;
	}

	public String[] renderValues() {
		String[] values = new String[fields.length];
		for (int i = 0; i < fields.length; i++) {
			if (fields[i] != null) {
				values[i] = definition.getField(i).rending(fields[i]);
			}
		}
		return values;
	}

	public String getFieldName(int index) {
		return definition.getField(index).getName();
	}

	public String[] getFieldNames() {
		String[] values = new String[definition.getFieldCount()];
		for (int i = 0; i < values.length; i++) {
			values[i] = getFieldName(i);
		}
		return values;
	}

	public int getFieldCount() {
		return fields.length;
	}

	public int getFieldIndex(String name) {
		int count = definition.getFieldCount();
		for (int i = 0; i < count; i++) {
			if (name.equalsIgnoreCase(getFieldName(i))) {
				return i;
			}
		}

		return -1;
	}

	// public DataField parse(int index, Object value) throws DataException {
	// fields[index] = definition.getField(index).parse(value);
	// return fields[index];
	// }
	//
	// public DataField parse(String name, Object value) throws DataException {
	// int i = getFieldIndex(name);
	// if (i != -1) {
	// fields[i] = definition.getField(i).parse(value);
	// return fields[i];
	// }
	//
	// return null;
	// }

	public DataRecord parse(Object[] values) throws DataException {
		int len = fields.length - values.length;
		if (len > 0) {
			for (int i = 0; i < values.length; i++) {
				fields[i] = definition.getField(i).parse(values[i]);
			}
		} else {
			for (int i = 0; i < fields.length; i++) {
				fields[i] = definition.getField(i).parse(values[i]);
			}
		}

		return this;
	}

	public DataField set(int index, Object value) throws DataException {
		fields[index] = definition.getField(index).newDataFieldInstance();
		fields[index].setValue(value);
		return fields[index];
	}

	public DataField set(String name, Object value) throws DataException {
		int i = getFieldIndex(name);
		if (i != -1) {
			fields[i] = definition.getField(i).newDataFieldInstance();
			fields[i].setValue(value);
			return fields[i];
		}

		return null;
	}

	public DataRecord set(Object[] values) throws DataException {
		int len = fields.length - values.length;
		if (len > 0) {
			for (int i = 0; i < values.length; i++) {
				DataField fd = definition.getField(i).newDataFieldInstance();
				fd.setValue(values[i]);
				fields[i] = fd;
			}
		} else {
			for (int i = 0; i < fields.length; i++) {
				DataField fd = definition.getField(i).newDataFieldInstance();
				fd.setValue(values[i]);
				fields[i] = fd;
			}
		}

		return this;
	}

	public boolean isValid() {
		return errors == null || errors.size() == 0;
	}

	public List<String> getErrors() {
		return errors;
	}

	public void appendError(String message) {
		if (errors == null) {
			errors = new ArrayList<String>();
		}

		errors.add(message);
	}

	public void clearErrors() {
		errors = null;
	}

	public DataTableDefinition getDefinition() {
		return definition;
	}

	public void validate() {
		// // TODO 这个版本错误会不发生
		// if (definition.getFieldCount() != fields.length) {
		// String msg = "Column count not match! Actual count:" + fields.length + ". Definition count:" + definition.getFieldCount();
		// // String msg = "エラー内容：項目数が定義と異なります。　データ:" + fieldValues.length + " 定義:" + columnDefinition.length;
		// appendError(msg);
		// }

		DataField[] fields = this.getFields();
		for (int i = 0; i < fields.length; i++) {
			DataField field = fields[i];
			if (field != null) {
				field.validate();
				if (field.isInvalid()) {
					this.appendError("Column" + (i + 1) + " [" + field.getDefinition().getName() + "] " + field.getErrors());
					// this.appendError("Column:" + (i + 1) + " " + field.getErrors());
				}
			}
		}
	}

	public boolean equals(DataRecord obj) {
		DataField[] objfields = obj.getFields();
		if (objfields.length != this.fields.length) {
			return false;
		}

		for (int i = 0; i < objfields.length; i++) {
			DataField dataField = objfields[i];
			if (dataField != null && this.fields[i] == null) {
				return false;
			}

			if (dataField == null && this.fields[i] != null) {
				return false;
			}

			if (dataField != null && this.fields[i] != null && !dataField.equals(this.fields[i])) {
				return false;
			}
		}

		return true;
	}

}
